package com.jl.service.impl;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jl.commons.constant.Constants;
import com.jl.commons.result.PageDataInfo;
import com.jl.commons.shiro.ShiroUser;
import com.jl.commons.utils.CopyBean;
import com.jl.commons.utils.MathMethodUtil;
import com.jl.commons.utils.TimeUtils;
import com.jl.mapper.*;
import com.jl.model.*;
import com.jl.model.in.ChangeCompnent;
import com.jl.model.in.FaultContent;
import com.jl.service.IFaultInfoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 故障信息表 服务实现类
 * </p>
 *
 * @author JiangJian
 * @since 2019-03-06
 */
@Service
public class FaultInfoServiceImpl extends ServiceImpl<FaultInfoMapper, FaultInfo> implements IFaultInfoService {

    @Autowired
    private KeyWordMapper keyWordMapper;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private DevicePartMapper devicePartMapper;

    @Autowired
    private DeviceComponentMapper deviceComponentMapper;

    @Autowired
    private DamageComponentMapper damageComponentMapper;

    @Autowired
    private DamagePartMapper damagePartMapper;

    @Autowired
    private InspectionTaskMapper inspectionTaskMapper;


    @Override
    public void selectFaultInfoDataGrid(PageDataInfo<Map<String, Object>> pageDataInfo, QueryWrapper<FaultInfo> qw) {
        Page<Map<String, Object>> page = new Page<>();
        page.setSize(pageDataInfo.getSize());
        page.setCurrent(pageDataInfo.getCurrent());
        List<Map<String, Object>> mapList = baseMapper.selectDataGrid(page, qw);
        pageDataInfo.setTotal(page.getTotal());
        pageDataInfo.setRecords(mapList);
    }

    @Override
    public boolean saveFaultInfo(ShiroUser currUser, FaultInfo faultInfo, List<String> tipsComponent) {
        //故障部位id
        List<Long> partIds = new ArrayList<>();
        List<String> partNames = new ArrayList<>();
        Long deviceId = faultInfo.getDeviceId();
        Device deviceInfo = deviceMapper.selectById(deviceId);
        Long modelId = faultInfo.getModelId();
        String modelName = faultInfo.getModelName();
        //更换配件id
        List<Long> componentIds = new ArrayList<>();

        Date now = new Date();
        faultInfo.setCreateId(currUser.getId());
        faultInfo.setGmtCreate(now);
        /*
            1、修改部位故障次数，修改设备的故障总时长的故障次数
            2、新增关键词绑定次数
            3、插入数据到更换配件(damage_component)表中
            4、重新计算设备配件(device_component)的寿命
            5、插入数据到damage_part中
            6、提示前端的配件寿命不正常的配件，要维修人员多注意
//            6、这里需要将故障的部位信息插入到另外一张表中，用于统计
            7、如果该设备的部位 或者 同类设备的部位已经发生过了这个故障，则表示需要发布一个临时巡检任务（待定具体计划详情）
         */
        String keyWordStr = faultInfo.getKeyWordId();
        if(StringUtils.isNotBlank(keyWordStr)){
            String[] keyWords = faultInfo.getKeyWordId().split(",");
            List<Long> kerWordIds = new ArrayList<>();
            for (String id : keyWords) {
                kerWordIds.add(Long.parseLong(id));
            }
            //完成关键词绑定次数
            keyWordMapper.updateKeyWordBindCountWithIds(kerWordIds, +1);
        }
        //处理完故障详情清晰，获得修改后的部位的id列表和更换配件(component)的id列表
        List<FaultContent> faultContentList = JSONObject.parseArray(faultInfo.getFaultContent(), FaultContent.class);
        for (FaultContent faultContent : faultContentList) {
            partIds.add(faultContent.getFaultPartId());
            partNames.add(faultContent.getFaultPartName());
            List<ChangeCompnent> changeComponents = faultContent.getChangeComponent();
            if (null != changeComponents && !changeComponents.isEmpty()) {
                List<Long> tempComponentIds = new ArrayList<>();
                for (ChangeCompnent changeCompnent : changeComponents) {
                    tipsComponent.add(changeCompnent.getComponentName());
                    tempComponentIds.add(changeCompnent.getComponentId());
                }
                componentIds.addAll(tempComponentIds);
            }
        }
        //所有故障的部位故障次数加1
        devicePartMapper.updatePartFaultCountWithIds(+1, partIds);

        //故障设备的故障次数加1  故障总时长加上该设备的停机时间
        deviceMapper.updateDeviceFaultCountAndTime(+1, faultInfo.getStopDuration(), deviceId);

        //获得所有更换了的配件信息
        List<DeviceComponent> deviceComponentList = new ArrayList<>();
        if (!componentIds.isEmpty()) {
            deviceComponentList = deviceComponentMapper.selectChangeDeviceComponent(deviceId, componentIds);
        }
        //插入damage_component表中数据，同时更新设备配件的平均寿命
        if (!deviceComponentList.isEmpty()) {
            updateDeviceComponentInfoAndInsertDamageComponent(tipsComponent, faultInfo, deviceComponentList,currUser.getId());
        }
        //查询之前是否有相同的故障，如果有故障则需要新增一条巡检指令(本月内)
        List<DevicePart> devicePartList = devicePartMapper.selectRepeatFailPart(modelId,partIds);
        if(null!= devicePartList && !devicePartList.isEmpty()){
            //暂定该修条维修的第一个维修人员
            Long operatorId = faultInfo.getMasterSolver();
            insertInspectionTask(devicePartList, modelId,modelName,deviceInfo,currUser.getId() ,operatorId);
        }

        baseMapper.insert(faultInfo);

        //插入数据到damage_part中，用于统计故障部位
        insertDamagePartInfo(partIds,partNames ,faultInfo, modelId,currUser.getId());
        return false;
    }

    /**
     *根据关键词搜索故障信息
     * @param pageDataInfo 分页参数
     * @param keyWordId 关键词id
     */
    @Override
    public void selectFaultInfoDataGridByKeyWordId(PageDataInfo<Map<String, Object>> pageDataInfo, Long keyWordId) {
        Page<Map<String, Object>> page = new Page<>();
        page.setSize(pageDataInfo.getSize());
        page.setCurrent(pageDataInfo.getCurrent());
        List<Map<String, Object>> mapList = baseMapper.selectFaultInfoByKeyWordId(page, keyWordId);
        pageDataInfo.setTotal(page.getTotal());
        pageDataInfo.setRecords(mapList);
    }

    @Override
    public void getFaultInfoByLineId(PageDataInfo<Map<String, Object>> pageDataInfo, Long lineId) {
        Page<Map<String, Object>> page = new Page<>();
        page.setSize(pageDataInfo.getSize());
        page.setCurrent(pageDataInfo.getCurrent());
        List<Map<String, Object>> mapList = baseMapper.selectFaultInfoByLineId(page, lineId);
        pageDataInfo.setTotal(page.getTotal());
        pageDataInfo.setRecords(mapList);
    }

    @Override
    public void selectDeviceFaultWithKeyWord(PageDataInfo<Map<String, Object>> pageDataInfo, Long keyWord, Long deviceId) {
        Page<Map<String, Object>> page = new Page<>();
        page.setSize(pageDataInfo.getSize());
        page.setCurrent(pageDataInfo.getCurrent());
        List<Map<String, Object>> mapList = baseMapper.selectDeviceFaultWithKeyWord(page, keyWord, deviceId);
        pageDataInfo.setTotal(page.getTotal());
        pageDataInfo.setRecords(mapList);
    }

    @Override
    public boolean addFaultInfoAcceptNum(Long id) {
        return baseMapper.updateFaultInfoAcceptNum(id, 1) > 0;
    }

    /**
     * 更换零件
     * 更新零件的启用时间
     * 新增损坏零件
     * 更新零件寿命
     */
    private void updateDeviceComponentInfoAndInsertDamageComponent(List<String> tipsComponent, FaultInfo faultInfo, List<DeviceComponent> deviceComponentList, Long createdId) {
        //判断是否与过去统计的寿命相差太大，小于一半值以上,需要进行提醒
        for (DeviceComponent deviceComponent : deviceComponentList) {
            //设备故障时间 - 配件启用时间  = 配件使用天数
            Integer useDays = TimeUtils.getIntervalDays(deviceComponent.getStartTime(),faultInfo.getFaultTime());
            if (useDays < (deviceComponent.getAvgLife() / 2)) {
                tipsComponent.add(deviceComponent.getName());
            }
            //生产损坏零件信息，并修改零件信息中的启用时间和计算使用寿命
            DamageComponent damageComponent = CopyBean.deviceComponentToDamageComponent(createdId, faultInfo, deviceComponent);
            //更新device_component的平均寿命
            Integer median = 0;
            //先插入故障配件信息，然后重新计算配件平均寿命
            if(damageComponentMapper.insert(damageComponent)>0){
                List<Integer> integerList = damageComponentMapper.selectDeviceComponentLifeWithComId(damageComponent.getDeviceId(), damageComponent.getComponentId());
                if (!integerList.isEmpty()) {
                    median = MathMethodUtil.getMedian(integerList);
                }
                if (median != 0) {
                    deviceComponent.setAvgLife(median);
                }
                deviceComponentMapper.updateById(deviceComponent);
            }
        }
    }

    /**
     * 插入故障部位信息
     */
    private void insertDamagePartInfo(List<Long> partIds,List<String> partNames ,FaultInfo faultInfo,Long modelId,Long createdId){
        Long deviceId = faultInfo.getDeviceId();

        Date now = new Date();
        Date faultTime = faultInfo.getFaultTime();
        Date solveTime = faultInfo.getSolveTime();
        List<DamagePart> damagePartList = new ArrayList<>();
        for (int index = 0; index < partIds.size(); index++) {
            DamagePart damagePart =new DamagePart();
            damagePart.setFaultId(faultInfo.getId());
            damagePart.setLineId(faultInfo.getProductionLine());
            damagePart.setModelId(modelId);
            damagePart.setDeviceId(deviceId);
            damagePart.setDeviceNumber(faultInfo.getDeviceNumber());
            damagePart.setPartId(partIds.get(index));
            damagePart.setPartName(partNames.get(index));
            damagePart.setFaultTime(faultTime);
            damagePart.setSolveTime(solveTime);
            damagePart.setStatus(Constants.NORMAL_STATUS);
            damagePart.setCreateId(createdId);
            damagePart.setGmtCreate(now);
            damagePartList.add(damagePart);
        }
        damagePartMapper.insertBatch(damagePartList);
    }

    /**
     * 插入临时指令
     */
    private void insertInspectionTask(List<DevicePart> devicePartList,Long modelId,String modelName,Device device,Long createId ,Long operatorId){
        InspectionTask inspectionTask =new InspectionTask();
        JSONObject jsonObject = new JSONObject();
        JSONArray contentArray = new JSONArray();
        jsonObject.put("deviceName",device.getName()+"("+device.getNumber()+")");
        jsonObject.put("deviceId",device.getId());
        JSONArray partArray = new JSONArray();
        for(DevicePart devicePart : devicePartList){

            JSONObject partObj = new JSONObject();
            partObj.put("partId",devicePart.getId());
            partObj.put("partName",devicePart.getName());
            //部位巡检概要
            partObj.put("content",devicePart.getDescription());
            partArray.add(partObj);
        }
        jsonObject.put("deviceParts",partArray);
        contentArray.add(jsonObject);
        Date now = new Date();
        String name = String.format("%s临时巡检-%s",device.getNumber(),TimeUtils.parseDateToStr(now,"YYYY年MM月dd日"));
        inspectionTask.setName(name);
        String description = String.format("%s类型出现重复故障，临时进行巡检操作！！",modelName);
        inspectionTask.setDescription(description);
        inspectionTask.setModelId(modelId);
        //这里的开始时间默认就是完成故障的时候
        inspectionTask.setStartTime(now);
        inspectionTask.setContent(contentArray.toJSONString());
        //默认不设置执行人
        //inspectionTask.setOperatorId(operatorId);
        inspectionTask.setStatus(Constants.NORMAL_STATUS);
        inspectionTask.setIsTemp(Constants.FAULT_TASK);
        inspectionTask.setGmtCreate(now);
        inspectionTask.setCreateId(createId);
        inspectionTaskMapper.insert(inspectionTask);
    }

    /***********************************************/

    @Override
    public void getRepeatFaultSymptom(PageDataInfo<Map<String, Object>> pageDataInfo, String startTime, String endTime) {
        List<Map<String, Object>> maps = baseMapper.selectSameDeviceAndSameSymptomFaultInfo(startTime,endTime);
        pageDataInfo.setCurrent(Constants.FIRST_PAGE);
        pageDataInfo.setSize(maps.size());
        pageDataInfo.setTotal(maps.size());
        pageDataInfo.setRecords(maps);

    }

}
